메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

싱글톤을 이용한 네트워크 관리 패턴

한빛미디어

|

2004-11-04

|

by HANBIT

14,481

저자: Stephen B. Morris, 한동훈 역
원문: http://www.onjava.com/pub/a/onjava/2004/10/27/NMSingleton.html

서비스 중심의 네트워크(Service-driven networking)는 사용자 요청에 대응하기 위해 빠르고 자동화된 예측이 필요하다. 할당된 대역폭을 증가시키거나 서비스 제공자로부터 대역폭을 크게 차지하는 최신 게임을 액세스한다고 가정해보자. 온라인 신청서를 작성하고, 서비스를 제공하는 서버에서 프로파일을 업데이트 한 후에 필요한 리소스에 접근할 수 있다. 서비스 제공자는 이런 종류의 고객 요청을 수행하기 위해 최적화하는 것이다. 명령 수행의 속도와 정확성이 생명인 것이다.

이러한 서비스의 핵심적인 요소는 서비스 제공 서버(provisioning server)다. 서비스 제공 서버는 요청받은 서비스를 제공하기 위해 네트워크를 변경하는 소프트웨어를 의미한다. 여기서는 간단하면서 확장성있는 서비스 공급 서버를 구현하기 위해 싱글톤(Singleton) 패턴을 사용하는 방법에 대해 설명할 것이다.

이 기사를 위한 좋은 참고자료는 Craig Larman의 Applying UML and Patterns가 있다. Larman의 책에서 언급된 것처럼 패턴을 사용함에 있어 주된 장점은 상당히 복잡한 소프트웨어를 완벽하게 작성할 수 있게 해주는 속도에 있다. 패턴의 다른 장점은 아키텍트, 설계자, 개발자가 공통된 어휘를 갖게 해주기 때문에 머신의 바깥에서 또는 코드의 바깥에서 생각하는 것을 도와준다는 것이다. 이러한 간단한 예는 아키텍트나 설계자가 “클래스 X는 클래스 Y와 느슨하게 결합(loosely coupled)되어야 합니다. 왜냐하면 Y는 다음 릴리스에서 변경될 수 있어요” 개발자는 X와 Y의 의존성을 최대한 적게끔 클래스를 작성할 것이다. 이처럼 패턴은 미래에 있을 불필요한 코드 변경을 줄여주는데 도움이 된다.

사람이 가진 소중한 시간을 가장 잘 투자하는 방법 중에 하나는 좋은 패턴 책을 읽고, 학습하고, 각 패턴의 다양한 변형들을 각자의 고유한 문제 영역에 맞게 생각해내려고 노력하는 것이다. 이것은 매우 어려운 일이지만 분명 매우 큰 보상을 가져다준다. 예를 들어, 프로젝트에 참여해서 매우 어려운 문제에 봉착한 경우 패턴이 필요할 때 마다 자신의 패턴 노트를 참고할 수 있으며, 이는 동시에 자신의 노트를 업데이트할 수 있는 좋은 기회이기도 하다. 패턴은 아웃소싱의 시대에 필수적인 전문직 종사자의 가치 사슬(Value Chain: 부가가치를 창출하는 과정)을 향상시키는 데 도움이 된다.

역주: practitioners라 하면 개업의, 변호사와 같은 전문직 종사자라는 의미로 쓰이며, 여기서는 IT 종사자 또는 전문직 종사자의 의미로 옮겼습니다.

격려(Service with a Smile)

여기서 하려는 일은 네트워크 서비스를 빠르게 전환하는 것이다. 이렇게 하기 위해, 네트워크와 상호 작용할 수 있어야하고, 서비스 제공자가 보다 큰 대역폭을 할당해주는 것과 같은 방식으로 설정과 상태를 변경할 수 있어야 한다. 이렇게 간단한 작업도 전기통신 네트워크에서 수행하는 것은 믿기 어려울 정도로 어렵다. 왜냐하면 이런 작업은 그림1에 있는 것처럼 서비스 포털, 데이터베이스, 네트워크 장치 같은 다양한 백엔드(back-end) 시스템과의 상호 연동이 필요하다.

역주: "Service with a Smile"은 관용구로 "격려"의 의미지만, "미소짓는 서비스”가 본문에는 더 적합해 보입니다.

그림1
그림1. 서비스 제공자 네트워크 계층(Service provider network layers)

이러한 복잡성에도 불구하고, 아래에서 살펴볼 것처럼 고객 중심의 네트워크 관리에 대한 요구가 높아지고 있다. 전기통신(telecom)이 유난히 복잡한 것은 전기통신이 갖는 본질적인 특징 즉, 사용자, 백엔드 시스템(서비스 공급 서버와 데이터베이스), 네트워크 장치(라우터 및 스위치)과 같이 3계층으로 이루어져 있기 때문이다. 사용자 중심의 서비스 변경 요청을 수행하기 위한 전형적인 워크플로우(workflow)를 간단하게 살펴보자.

워크플로우 예

그림 1에서 홈 오피스 사용자가 링크1의 광대역 연결을 올려달라는 온라인 요청을 한다. 마찬가지로, 헤드쿼터(headquarter) 사이트에서도 링크2에 대한 대역폭을 올려달라는 요청을 한다. 이들 요청은 그림1에 나타나 있지는 않지만 변경 요청을 검증하는 몇 가지 워크 플로우 시스템을 통해서 전달된다. 변경 요청이 그림1의 라우터에 명령 형태로 적용되는 일련의 디바이스 설정 명령으로 변환된다.

간단한 사용자 중심의 GUI 프론트로 그림1의 서비스 공급 서버와 통신하는 워크플로우를 시뮬레이트 해볼 것이다. 이 GUI 프로그램은 전형적으로 브라우저를 사용하여 액세스하며, 백엔드 시스템(여기서는 데이터베이스에 요청을 저장하는 작업)과 관련 네트워크 디바이스에 요청된 변경사항을 적용한다.

이 모든 복잡한 것들 중에서 요구되는 기능들을 빠르게 구현할 수 있는 방법이 필요하다. 패턴이 그에 대한 해결책이다! 주요 요구사항들을 간단하게 리뷰해보자.
  • 사용자 인터페이스는 제한된 서비스 화면과 변경 요청만 할 수 있다.
  • 서비스 공급 서버에서 하나의 인스턴스가 모든 변경 요청을 처리한다.
  • 서비스 공급 서버는 백엔드 시스템(데이터베이스 및 네트워크 디바이스)을 업데이트한다.
그림1에서 사용자에겐 기본 GUI가 필요하다. 이 GUI 기능은 종종 네트워크 고객 관리라 하며, 점차로 서비스 공급자 네트워크의 기능이 되어가고 있다. 가장 인기 있는 네트워크 고객 관리 기능은 서비스 수준의 가용성 모니터링 (service-level assurance monitoring)이다. 이것은 2MB 전송속도, 20ms의 라운드 트립 지연과 같이 사용자가 계약한 서비스 수준 동의 내용을 조회할 수 있다. 고객이 지나치게 많은 트래픽을 유발하여 계약을 어기는 경우, 공급하는 이러한 트래픽을 감소시킬 수 있다. 서비스 공급자가 네트워크 혼잡 상태에서 트래픽을 감소하거나 지연시키는데 실패하는 것과 같이 요구사항을 준수하는데 실패하면 고객은 금전적인 보상을 받을 수 있다. 이와 같이 동작하는 인프라스트럭쳐를 구축하는 것은 현대 네트워크 관리의 첨단이라 할 수 있다.

여기서 소개하는 서비스 공급 서버는 모든 서비스 변경 요청을 처리하며, 이러한 요청을 다른 백엔드 시스템에 대한 인증을 위해 전달한다. 이와 같은 분배는 서비스 공급 서버 자체의 부하를 줄이는 데 도움이 된다.

서비스 공급 서버는 하나의 인스턴스를 제공하고, 명령을 받고, 복잡한 백엔드 시스템을 업데이트하는 작업에 중점을 둔다. 네트워크 관리에서, 하나의 공급 서버 인스턴스를 유지하는 것은 핵심적인 요구사항이다. 요청은 이 예제에서 사용하는 것처럼 인트라-JVM 정적 액세스(static access)나 또는 RMI, CORBA 등을 사용하여 이 인스턴스에 전달된다. 일반적으로 서버 소프트웨어는 하나의 시스템에만 설치되고, 클라이언트는 서버가 제공하는 기능에 액세스한다. 이것은 오직 서버 코드 하나만 적용하여 서버 코드의 인스턴스를 여러 개 갖는 것을 피하기 위한 것이다. 즉, 서비스 공급 서버에 싱글톤 패턴을 적용하는 것은 좋은 선택이다.

싱글톤 패턴

싱글톤 패턴은 JVM 환경에서 클래스의 인스턴스를 하나만 유지하고자 할 때 사용된다. 싱클톤 패턴은 기능에 대해서 하나의 시작점만 필요한 응용 프로그램에 어용하다. 예를 들어, 우리의 예제에서는 요청 수행과 같은 것을 들 수 있다. 전기통신(telecom) 세상으로 한정하면, 라우터나 오래된 네트워크 요소들과 같은 디바이스 사용을 요청하는 데 있어 매우 중요하다. 즉, 디바이스가 폭주하지 않도록 미리 지정된 수신율로 설정 명령을 순서대로 보내는 데 있어 하나의 인스턴스를 유지하는 것이 중요하다.

대부분의 경우에, 디바이스는 트래픽 처리 코드보다 낮은 우선순위로 네트워크 관리 기능을 수행한다. 네트워크 기기들은 네트워크 관리 명령에 대응하는 것 뿐만 아니라 많은 작업을 처리한다는 것을 기억해야 한다. 게다가, 네트워크 기술 속도와 반응이 더 증가하고 있다.
실제로, 리소스 사용은 싱글톤 패턴을 사용해서 제어할 수 있다.

서비스 명령 GUI

서비스 명령 GUI는 단순하다. 사용자가 자신의 서비스의 현재 설정을 보고 업데이트할 수 있게 해준다. 홈 오피스 사용자의 경우 그림1의 링크1에서 56kbps의 속도로 연결되어 있으며, 기업 사용자의 경우 링크2에 5Mbps로 연결되어 있다. 내친김에 더 얘기하자면, kilo-나 mega-라는 단위는 저장매체에서 쓰이는 1024나 1,048,576을 의미하는것이 아니라 정확히 1000과 1,000,000을 의미한다. 따라서 56kbps는 56,000bps를, 5Mbps는 5,000,000bps를 의미한다.

홈 오피스 사용자가 로또에 당첨되서 인터넷 연결을 1Mbps로 업그레이드하기로 결정했다고 하자. 그는 서비스 설정 프로그램으로 달려가서 그림2에 있는 GUI를 본다. 이것은 부유한 홈 오피스 사용자에게 허용되는 서비스다.

그림2
그림2. 서비스 설정

현재 설정된 서비스 수준은 56kbps이며, 그림2의 포털에서 3가지 선택사항을 선택할 수 있다.
  • Update Profile: 설정 변경
  • Undo: 최근 설정 변경사항을 취소한다
  • Exit: 프로그램을 종료한다
1Mbps로 서비스를 업데이트하기 위해 업데이트 옵션을 선택하는 것은 그림 3처럼 서비스 공급 서버에 명령을 보내는 것을 의미한다. 이 명령은 서버로 전달되고 결과는 그림 3과 같다.

그림3
그림3. 서비스 업그레이드 GUI

서비스 공급 서버

서비스 공급 서버는 싱글톤 패턴을 사용하여 클래스 하나로 구현할 수 있다. 중요한 부분은 GUI 명령을 담아둘 리스트 컬렉션이다. 실제 시스템에서는 서버를 RMI 또는 CORBA 종단점으로 구현해야 한다. 여기서는 훨씬 단순한 형태로 구현할 것이지만, 확장을 허용하는 형태로 할 것이다. 핵심 요소는 싱글톤 패턴의 사용이며, 서버 클래스는 private 생성자를 가지며, 자신을 가리키는 private static 인스턴스를 유지한다.

아래에서 보게 될 것처럼 서비스 공급 서버에서 리스트 컬렉션 관리는 동기화 된다. 서버 클래스는 하나의 인스턴스만 갖게 되고, 이는 다양한 스레드 액세스로부터 리스트를 보호하게 된다. 뿐만 아니라, 각 리스트 항목은 하나의 완전한 사용자 요청을 표현한다. 즉, 각 항목은 서버에서 최소단위수행(atomic operation)을 의미한다. 항목이 생성되면 클라이언트는 서버에 적절한 동작을 요청한다.

서버는 클라이언트에 공개 메서드 4개를 제공한다.
  • getInstance()
  • executeCommand()
  • undoCommand()
  • toString()
getInstance() 메서드는 서비스 공급 서버의 싱글톤 클래스에 대한 참조를 반환한다. 클라이언트는 이 참조를 이용하여 다른 메서드를 호출할 수 있다.
executeComment() 메서드는 서버에 요청을 전달한다. 이 명령은 동작 카운트, 사용자 ID 및 요청 세부사항과 같은 정보를 포함하는 텍스트 형태의 메시지로 전달된다. 요청은 리스트 객체에 추가된다. 서버는 JDBC를 사용해 데이터베이스에 이러한 세부사항을 적용하고 SNMP나 다른 디바이스 액세스 기술을 사용해 네트워크 라우터에 필요한 업데이트를 적용한다.

undoCommand()는 클라이언트의 GUI에서 요청한 가장 최근의 명력을 복원한다. 여기서 중요한 부분은 사용자 타입의 명령이 섞이지 않게 하는 것이다. 엔터프라이즈 네트워크 매니저가 명령을 복원하기로 결정한다면, 홈 오피스 사용자에게는 적용되지 않게 해야 한다.

toString() 메서드는 특정 사용자의 수행을 문자열 형태로 반환한다. 이 프로그램에서는 "Home Office User”와 "Enterprise User”와 같은 두 가지 유형의 사용자가 있다.

자바 코드 예

이 예제는 자바 클래스 3개로 구성된다.
  • RunPattern.java
  • ServicePortal.java
  • ProvServer.java
RunPattern.java는 소프트웨어를 실행한다. 이는 프로그램의 간단한 디스크립션을 읽어들고, 두 개의 GUI 사용자 인터페이스를 생성한다.(그림 2와 4) 해당 사용자는 GUI를 사용할 수 있고, 필요에 따라 서비스 공급자 링크를 업데이트할 수 있다. 웹 서비스와 같은 최종 시스템에서는 별도로 구현해야 한다.

public class RunPattern {
      public static void main(String [] arguments) {

            ServicePortal portal1 = new ServicePortal();
            portal1.createUserView("Home Office User",
            "Service - 56Kbps link");


            ServicePortal portal2 = new ServicePortal();
            portal2.createUserView("Enterprise User",
            "Service - 5Mbps link");

      }
}

ServicePortal.java

ServicePortal 클래스는 ProvServer 클래스와 결합된 간단한 스윙 GUI를 제공한다. GUI에서 버튼은 적절한 메서드를 호출한다.

      // Call into Prov Server to update portal
      public void refreshTextDisplay() {
            textDisplay.setText("Provisioning Server " +
            "Command History for " + userId +"\n" +
                  ProvServer.getInstance().toString(
                  userId));

      }

      public void actionPerformed(ActionEvent evt) {
            Object originator = evt.getSource();
            if (originator == updateService) {
             executeCommand(" " + userId +
                  " Increase bandwidth by 1Mbps");

            }
            else if (originator == undoButton) {
             undoCommand();
            }
            else if (originator == exitButton) {
                  exitApplication();
            }
      }

      private void executeCommand(String message) {
            ProvServer.getInstance().executeCommand(
            (++operationCount) + message);
            refreshTextDisplay();
      }

      private void undoCommand() {
            Object result =
            ProvServer.getInstance().
            undoCommand(userId);


      if (operationCount > 0)
      operationCount--;
      refreshTextDisplay();
      }
}

ProvServer.java

ProvServer 클래스는 필요한 서비스 공급 서버를 구현한다. 앞에서 기술한 것처럼 두 개의 private 멤버를 가진다. 하나는 요청 목록이며, 하나는 인스턴스 자신을 위한 것이다. 특히, 네트워크에 서비스 공급 서버가 하나만 설치된다고 가정하므로, 하나 이상의 인스턴스가 필요하지 않게 한다. 클라이언트는 getInstance() 메서드를 사용해서 다른 메서드에 액세스한다.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ProvServer {
      private List opList =
         Collections.synchronizedList(
         new ArrayList());
      private static ProvServer instance =
         new ProvServer();

      private ProvServer() {
   }

      public static ProvServer getInstance() {
            return instance;
      }

      public void executeCommand(String command) {
      opList.add(command + " Operation --> " +
         updateBackendSystems(command));
      }

      private String updateBackendSystems(
      String command) {
      return "Succeeded";
   }

      public String toString(String userId) {
            StringBuffer result = new StringBuffer();

            for (int i = 0; i < opList.size(); i++) {
                  if (((String) opList.get(i)).
                  indexOf(userId) != -1) {
                     result.append("   ");
                     result.append(opList.get(i));
                     result.append("\n");
                  }
            }
            return result.toString();
      }
}

결론

싱글톤 패턴은 한번 이상 인스턴스화 되지 않는 클래스이기 때문에 매우 좋은 선택이 될 수 있다. 일반적으로 패턴을 사용하게 되면 이 기사에서 작업한 경우처럼 간단하고, 기술적으로 멋진 솔루션을 제작할 수 있게 해준다. 싱글톤 패턴을 사용해서 얻을 수 있는 이점은 개발자가 복잡한 응용 프로그램 도메인 문제들을 해결하는데 매달리는 것을 예방할 수 있다는 것이다. 패턴의 사용은 견고한 패턴에 기반하여 보다 강력한 패턴들의 조합을 가능하게 하고, 응용 프로그램 가치를 올리는 기능에 보다 많은 시간을 집중할 수 있게 해준다. 게다가, 보다 나은 제품 차별화가 가능해진다.

서비스 공급 시스템을 구현하기 위해 어떤 미들웨어 코드도 사용하지 않았다. 일반적으로 이 코드는 SNMP, 명령줄 인터페이스와 같은 네트워크 디바이스 기술에 사용한다. 다음 기사에서는 SNMP(JDMK)와 JMX와 같은 기술들도 다룰 것이며, GoF의 Adapter 패턴을 적용할 것이다. Adapter 패턴은 기술의 복잡한 부분을 은폐하는데 있어 필수적이다.

패턴은 최상의 소프트웨어 개발을 위해 디자인에 대한 풍부한 토대를 제공한다. 싱글 인스턴스 컨트롤과 같은 일반화된 중요한 문제를 해결해 주기 때문에 모든 소프트웨어 개발자에게 패턴은 없어서는 안될 도구가 되어야 한다. 패턴은 반복되는 어려운 문제들에 대한 빠른 해결책을 제공해준다.
패턴이 내 마음에 특히 와 닿는 이유는 패턴을 적용한 응용 프로그램이 산업 영역(industry segments)을 넘어갈 수 있다는 것이다. 다시 말해서, 패턴을 이해하고 패턴을 폭넓게 적용하기 위해 정직한 노력을 기울인다면 이 지식을 다른 산업에 적용할 수 있다는 것이다. 예를 들어, 패턴을 사용하는 개발자는 해당 분야에 대한 약간의 훈련을 거치면 전기통신(telecom) 영역에서 재정(finance) 시스템 영역으로 옮기는 것도 가능하다.

리소스
TAG :
댓글 입력
자료실

최근 본 책0